package com.study.mike.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.study.mike.common.constants.RedisKey;
import com.study.mike.common.enums.BizCodeEnum;
import com.study.mike.common.exception.BizException;
import com.study.mike.common.utils.TreeUtil;
import com.study.mike.mapper.RoleMapper;
import com.study.mike.mapper.RoleResourceMapper;
import com.study.mike.model.dto.GrantRoleResourceDTO;
import com.study.mike.model.dto.QueryRoleDTO;
import com.study.mike.model.entity.Role;
import com.study.mike.model.entity.RoleResource;
import com.study.mike.model.po.*;
import com.study.mike.service.RoleResourceService;
import com.study.mike.service.RoleService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author KangHui
 * @Date 2022/8/19 16:20
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RoleResourceMapper roleResourceMapper;

    @Resource
    private RoleResourceService roleResourceService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = RedisKey.ONE_HOUR + ":role", allEntries = true)
    public Role addRole(AddRolePO po) {
        return this.operationRole(po);
    }

    @Override
    @Cacheable(cacheNames = RedisKey.ONE_HOUR + ":role", key = "#root.method.name + #po.pageCurrent + #po.pageSize")
    public Page<QueryRoleDTO> queryRole(QueryRolePO po) {
        // 构建查询参数
        IPage<Role> page = new Page<>(po.getPageCurrent(), po.getPageSize());
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(po.getRoleName()), Role::getRoleName, po.getRoleName());
        IPage<Role> pages = this.page(page, wrapper);
        List<Role> roles = pages.getRecords();
        // 获取查询结果列表
        List<QueryRoleDTO> collect = roles.stream().map(item -> {
            QueryRoleDTO roleDTO = new QueryRoleDTO();
            BeanUtils.copyProperties(item, roleDTO);
            return roleDTO;
        }).collect(Collectors.toList());
        // 数据转换 返回
        Page<QueryRoleDTO> result = new Page<>(pages.getCurrent(), page.getSize(), pages.getTotal());
        result.setRecords(collect);
        return result;
    }

    @Override
    @CacheEvict(value = RedisKey.ONE_HOUR + ":role", allEntries = true)
    public Role editRole(EditRolePO po) {
        /**
         * 操作数存在验证
         */
        Role role = this.getRoleInfoByID(po.getId());
        if (ObjectUtil.isNull(role)) {
            throw new BizException("400", "操作数不存在");
        }
        return this.operationRole(po);
    }

    @Override
    public List<GrantRoleResourceDTO> grantRoleResourceList(List<Integer> roleId) {
        List<GrantRoleResourceDTO> list = roleResourceMapper.grantRoleResourceList(roleId);
        return (List<GrantRoleResourceDTO>) TreeUtil.buildTree(list);
    }

    @Override
    public Boolean grantRoleResource(GrantRoleResourcePO po) {
        List<RoleResource> addRoleResource = new ArrayList<>();
        List<RoleResource> updateRoleResource = new ArrayList<>();
        po.getResourceDTOS().forEach(item -> {
            if (ObjectUtil.isNull(item.getRoleResourceId())) {
                RoleResource roleResource = new RoleResource();
                roleResource.setEnable(item.getEnable());
                roleResource.setResourceId(item.getResourceId());
                roleResource.setRoleId(po.getRoleId());
                addRoleResource.add(roleResource);
            } else {
                // 更新角色资源为禁用状态
                RoleResource roleResource = new RoleResource();
                roleResource.setEnable(item.getEnable());
                roleResource.setResourceId(item.getResourceId());
                roleResource.setRoleId(po.getRoleId());
                roleResource.setId(item.getRoleResourceId());
                updateRoleResource.add(roleResource);
            }
        });
        // 新增操作
        if (ObjectUtil.isNotEmpty(addRoleResource)) {
            roleResourceService.saveBatch(addRoleResource);
        }

        if (ObjectUtil.isNotEmpty(updateRoleResource)) {
            roleResourceService.saveOrUpdateBatch(updateRoleResource);
        }
        return true;
    }

    @Override
    public List<Role> sortOther(SortOtherPO po) {
        return roleMapper.sortOther(po);
    }

    /**
     * 操作新增、更新
     *
     * @param t
     */
    private Role operationRole(Object t) {
        Role role = new Role();
        // 传入角色存在验证
        try {
            BeanUtils.copyProperties(t, role);
            this.saveOrUpdate(role);
        } catch (DuplicateKeyException e) {
            // 手动回滚
            if (ObjectUtil.isNull(role.getId())) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            throw new BizException(BizCodeEnum.ROLE_EXIT.getCode(), BizCodeEnum.ROLE_EXIT.getMsg());
        }
        return role;
    }

    /**
     * 通过id获取角色信息
     */
    private Role getRoleInfoByID(Long id) {
        return this.getById(id);
    }
}
